/* 
 * File:   LibraryInterface.h
 * Author: sergey
 *
 * Общий интерфейс для описания классов библиотек. Наследники этой библиотеки
 * будут реализовывать различные методы хранения. Все наследники будут использовать
 * шаблон, основанный на LibraryInfo.
 * 
 * Created on 3 Декабрь 2009 г., 19:32
 */

#ifndef _LIBRARYINTERFACE_H
#define	_LIBRARYINTERFACE_H

#include <iostream>
#include <string>
#include <fstream>
#include <vector>

typedef unsigned long long UInt64;
typedef unsigned long      UInt32;
typedef unsigned char      UInt8;

template <size_t N> struct IntList {};
template <> struct IntList<1> {typedef UInt32 type;};
template <> struct IntList<2> {typedef UInt32 type;};
template <> struct IntList<3> {typedef UInt32 type;};
template <> struct IntList<4> {typedef UInt32 type;};
template <> struct IntList<5> {typedef UInt64 type;};
template <> struct IntList<6> {typedef UInt64 type;};
template <> struct IntList<7> {typedef UInt64 type;};

/*
 * Класс LibraryInfo используется для хранения преинформации о классе булевых
 * функций: местность функции, длина функции и количество функций в таком классе.
 * Так же для удобства хранится LibraryInfo для класса меньшего числа аргументов и
 * тип integer оптимальный для хранения такой функции.
 */
template <size_t N>
struct LibraryInfo {
    enum {
        n  = static_cast<UInt32>(N),                // n
        aC = 1UL << N,           // длина функции
        fC = 1ULL << (1 << N)     // общее количество функций
    };
    typedef LibraryInfo<N - 1> pre;
    typedef IntList<N> integer;            // integer, который будет использоваться для хранения функции
};

/*
 * LibraryInterface - абстрактный класс для описания библиотек.
 * В нем описаны методы для получения сложности функции и установки сложности
 * (getter и setter). Так же описаны методы загрузки и сохранения библиотеки
 * (описаны методы для работы с жестким диском).
 */
class LibraryInterface {
public:
    LibraryInterface();
    ~LibraryInterface();
    
    // функция для получения сложности функции f
    inline void get(const UInt64 f, UInt8 &s) { }
    // функция для установки сложности функции f (разрешено не создавать эту функцию)
    inline void set(const UInt64 f, const UInt8 s) { }
    // функция, которая проверяет "определена ли сложность данной функции"
    inline bool isSet(const UInt64) { }
    // функция загрузки из указанного бинарного файла
    void load(const std::string filename) { }
    // функция сохранения библиотеки в указанный бинарный файл
    void save(const std::string filename) { }

    void reset() {
        this->isEmptyRead4bitBuffer = true;
        this->isEmptyWrite4bitBuffer = true;
    }

protected:
    void readFileOpen(const std::string filename);
    void readFileClose();
    void read4bit(UInt8 &s);
    inline bool iseof() {
        return readBinFile.eof();
    }

    template <typename I> void readInt(I &s) {
        readBinFile.read((char*)(&s), sizeof(I));
    }

    template <typename I> void readIntVector(std::vector<I> &v, const UInt64 offset) {
        v.resize(offset);
        readBinFile.read((char*)v.data(), sizeof(I) * offset);
    }
    
    void writeFileOpen(const std::string filename);
    void writeFileClose();
    void write4bit(const UInt8 s);

    template <typename I> void writeInt(const I s) {
        _write4bit();
        writeBinFile.write((char*)(&s), sizeof(I));
    }
    
    template <typename I> void writeIntVector(std::vector<I> &v) {
        _write4bit();
        if (v.size() == 0) return ;
        writeBinFile.write((char*)v.data(), sizeof(I) * v.size());
    }

private:
    std::ofstream writeBinFile;
    std::ifstream readBinFile;
    UInt8 write4bitBuffer, read4bitBuffer;
    bool isEmptyWrite4bitBuffer, isEmptyRead4bitBuffer;
    void _write4bit();

};

#endif	/* _LIBRARYINTERFACE_H */

